<!DOCTYPE HTML>
<html>
<head>
<title>Process | AutoHotkey</title>
<meta name="description" content="The Process command performs one of the following operations on a process: checks if it exists; changes its priority; closes it; waits for it to close." />
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
<script type="text/javascript">$(function(){0<=window.navigator.userAgent.toLowerCase().indexOf("ucbrowser")&&CaoNiMaDeUc()})</script>
</head>
<body>

<h1>Process</h1>

<p>对进程执行下列的其中一个操作: 检查进程是否存在; 改变进程的优先级; 关闭进程; 等待进程关闭.</p>
<pre class="Syntax"><span class="func">Process</span>, <a href="#SubCommands">SubCommand</a> <span class="optional">, PIDOrName, Value</span></pre>

<h2 id="Parameters">参数</h2>
<dl>
    <dt>SubCommand, Value</dt>
    <dd>他们互相依赖, 其用法描述<a href="#SubCommands">如下</a>.</dd>

    <dt>PIDOrName</dt>
    <dd>
        <p>此参数可以为下面的数字(PID) 或进程名称. 它还可以被留空来改变脚本自己的优先级.</p>
        <p><strong>PID:</strong> 进程 ID, 唯一标识一个特定进程的数字(只有在此进程的生存期这个数字才有意义). 新运行的进程的 PID 可以通过 <a href="Run.htm">Run</a> 命令获取. 同样的, 窗口的 PID 可以通过 <a href="WinGet.htm">WinGet</a> 获取. Process 命令自身也可以获取 PID.</p>
        <p><strong>Name:</strong> 进程的名称, 通常和它的可执行文件名相同(不带路径), 例如 notepad.exe 或 winword.exe. 一个名称可能匹配多个正在运行的进程, 但只会对第一个进程进行操作. 这个名称不区分大小写.</p>
    </dd>
 </dl>

<h2 id="SubCommands">子命令</h2>
<p>对于 <em>SubCommand</em>, 指定以下命令之一:</p>
<ul>
    <li><a href="#Exist">Exist</a>: 检查指定的进程是否存在.</li>
    <li><a href="#Close">Close</a>: 强制关闭第一个匹配进程.</li>
    <li><a href="#List">List</a>: 还没有实现.</li>
    <li><a href="#Priority">Priority</a>: 更改首个匹配进程的优先级.</li>
    <li><a href="#Wait">Wait</a>: 等待指定的进程存在.</li>
    <li><a href="#WaitClose">WaitClose</a>: 等待所有匹配进程关闭.</li>
</ul>

<h3 id="Exist">Exist</h3>
<p>检查指定的进程是否存在.</p>
<pre class="Syntax"><span class="func">Process</span>, Exist <span class="optional">, PIDOrName</span></pre>
<p>如果存在一个匹配的进程则设置 <a href="../misc/ErrorLevel.htm">ErrorLevel</a>  为此进程 ID(PID), 否则为 0. 如果 <em>PIDOrName</em> 参数为空, 则获取脚本自身的 PID. 检索脚本的另一种单行的方法是 <code>PID := DllCall("GetCurrentProcessId")</code>.</p>

<h3 id="Close">Close</h3>
<p>强制关闭第一个匹配的进程.</p>
<pre class="Syntax"><span class="func">Process</span>, Close <span class="optional">, PIDOrName</span></pre>
<p>如果成功终止一个匹配的进程, 则设置 <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 为此进程原来的进程 ID(PID). 否则(没有找到匹配的进程或在终止匹配进程的过程中出现了问题) 它被设置为 0. 因为进程会被突然终止(可能在一个关键点中断它的工作或导致窗口中未保存数据的丢失), 因此只有当无法使用 <a href="WinClose.htm">WinClose</a> 作用于它的窗口来关闭相应进程时才使用这种方法.</p>

<h3 id="List">List</h3>
<p>虽然这个子命令还没有得到支持, <a href="#ListEx">示例 #4</a> 演示了如何通过 <a href="DllCall.htm">DllCall()</a> 检索进程列表.</p>

<h3 id="Priority">Priority</h3>
<p>更改第一个匹配进程的优先级.</p>
<pre class="Syntax"><span class="func">Process</span>, Priority, PIDOrName, Level</pre>
<p>更改首个匹配进程的优先级(如同 Windows 任务管理器中看到的那样)为 <em>Level</em>, 并设置 <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 为它的进程 ID(PID). 如果 <em>PIDOrName</em> 参数为空, 则改变脚本自己的优先级. 如果没有找到匹配的进程或在改变匹配进程的优先级过程中出现了问题, 则 ErrorLevel 被设置为 0.</p>
<p><em>Level</em> 应该为下列字母或单词的其中一个: L(或 Low)(低), B(或 BelowNormal)(低于标准), N(或 Normal)(普通), A(或 AboveNormal)(高于标准), H(或 High)(高), R(或 Realtime)(实时). 注: 任何不是设计为 Realtime 优先级运行的进程如果设置为这个优先级可能会降低系统的稳定性.</p>

<h3 id="Wait">Wait</h3>
<p>等待指定的进程存在.</p>
<pre class="Syntax"><span class="func">Process</span>, Wait, PIDOrName <span class="optional">, Timeout</span></pre>
<p><em>Timeout</em> 指定秒数(可以为小数) 以便在超时前等待. 如果忽略 <em>Timeout</em>, 子命令将无限期地等待. 如果发现匹配进程, <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 设置为其进程ID(PID). 如果子命令超时, ErrorLevel 设置为 0.</p>

<h3 id="WaitClose">WaitClose</h3>
<p>等待<strong>所有</strong>匹配进程关闭.</p>
<pre class="Syntax"><span class="func">Process</span>, WaitClose, PIDOrName <span class="optional">, Timeout</span></pre>
<p><em>Timeout</em> 指定秒数(可以为小数) 以便在超时前等待. 如果忽略 <em>Timeout</em>, 子命令将无限期地等待. 如果所有的匹配进程都关闭了, <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 设置为 0. 如果子命令超时, ErrorLevel 设置为仍然存在的首个匹配进程的 ID(PID).</p>

<h2 id="ErrorLevel">ErrorLevel</h2>
<p>如果子命令失败或超时, <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 设置为 0. 否则, 它将被设置为进程 ID(PID). 有关详细信息, 请参阅上面的子命令.</p>

<h2 id="Remarks">备注</h2>
<p>对于 <a href="#Wait">Wait</a> 和 <a href="#WaitClose">WaitClose</a> 子命令: 每隔 100 毫秒检查目标进程一次; 当条件满足时, 子命令停止等待. 换句话说, 它不会等待超时过期, 而是像上面描述的那样立即设置 <a href="../misc/ErrorLevel.htm">ErrorLevel</a>, 然后继续执行脚本. 此外, 当子命令处于等待状态时, 可以通过<a href="../Hotkeys.htm">热键</a>, <a href="Menu.htm">自定义菜单</a>或<a href="SetTimer.htm">计时器</a>启动新<a href="../misc/Threads.htm">线程</a>.</p>

<h2 id="Related">相关</h2>
<p><a href="Run.htm">Run</a>, <a href="WinGet.htm">WinGet</a>, <a href="WinClose.htm">WinClose</a>, <a href="WinKill.htm">WinKill</a>, <a href="WinWait.htm">WinWait</a>, <a href="WinWaitClose.htm">WinWaitClose</a>, <a href="WinExist.htm">WinExist()</a></p>

<h2 id="Examples">示例</h2>

<div class="ex" id="ExBasic">
<p><a class="ex_number" href="#ExBasic"></a> 启动记事本, 将其优先级设置为 "High" 并显示当前的 PID.</p>
<pre>Run notepad.exe,,, NewPID
Process, Priority, %NewPID%, High
MsgBox The newly launched Notepad's PID is %NewPID%.</pre>
</div>

<div class="ex" id="ExAdvanced">
<p><a class="ex_number" href="#ExAdvanced"></a> 对于记事本的出现, 最多等待 5.5 秒. 如果记事本出现在此秒数内, 则其优先级设置为 "Low", 并且脚本自身的优先级设置为 "High". 之后, 记事本将被关闭, 如果在 5 秒内未关闭, 将显示一个消息框.</p>
<pre>Process, Wait, notepad.exe, 5.5
NewPID := ErrorLevel  <em>; 由于 ErrorLevel 会经常发生改变, 所以要立即保存这个值.</em>
if not NewPID
{
    MsgBox The specified process did not appear within 5.5 seconds.
    return
}
<em>; 否则:</em>
MsgBox A matching process has appeared (Process ID is %NewPID%).
Process, Priority, %NewPID%, Low
Process, Priority,, High  <em>; 把脚本自己设置为高优先级.</em>
WinClose Untitled - Notepad
Process, WaitClose, %NewPID%, 5
if ErrorLevel <em>; PID 仍然存在.</em>
    MsgBox The process did not close within 5 seconds.</pre>
</div>

<div class="ex" id="ExHotkey">
<p><a class="ex_number" href="#ExHotkey"></a> 按下热键改变活动窗口进程优先级.</p>
<pre>#z:: <em>; Win+Z 热键</em>
WinGet, active_pid, PID, A
WinGetTitle, active_title, A
Gui, 5:Add, Text,, Press ESCAPE to cancel, or double-click a new`npriority level for the following window:`n%active_title%
Gui, 5:Add, ListBox, vMyListBox gMyListBox r5, Normal|High|Low|BelowNormal|AboveNormal
Gui, 5:Add, Button, default, OK
Gui, 5:Show,, Set Priority
return

5GuiEscape:
5GuiClose:
Gui, Destroy
return

MyListBox:
if (A_GuiEvent != "DoubleClick")
    return
<em>; 否则直接进入下一个标签:</em>
5ButtonOK:
GuiControlGet, MyListBox
Gui, Destroy
Process, Priority, %active_pid%, %MyListBox%
if ErrorLevel
    MsgBox Success: Its priority was changed to "%MyListBox%".
else
    MsgBox Error: Its priority could not be changed to "%MyListBox%".
return</pre>
</div>

<div class="ex" id="ListEx">
<p<a class="ex_number" href="#ListEx"></a> 使用 <a href="DllCall.htm">DllCall()</a> 获取正在运行的进程列表然后显示在消息框中.</p>
<pre>d := "  |  "  <em>; 字符串分隔符</em>
s := 4096  <em>; 缓存和数组的大小(4 KB)</em>

Process, Exist  <em>; 设置 ErrorLevel 为这个正在运行脚本的 PID.</em>
<em>; 使用 PROCESS_QUERY_INFORMATION(0x0400) 获取此脚本的句柄:</em>
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel, "Ptr")
<em>; 打开此进程的可调整的访问令牌(TOKEN_ADJUST_PRIVILEGES = 32):</em>
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
VarSetCapacity(ti, 16, 0)  <em>; 特权结构</em>
NumPut(1, ti, 0, "UInt")  <em>; 特权数组中的一个条目...</em>
<em>; 获取调试特权的本地唯一标识符:</em>
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
NumPut(luid, ti, 4, "Int64")
NumPut(2, ti, 12, "UInt")  <em>; 启用这个特权: SE_PRIVILEGE_ENABLED = 2</em>
<em>; 使用新的访问令牌更新此进程的特权:</em>
r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &amp;ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", t)  <em>; 关闭此访问令牌句柄以节约内存.</em>
DllCall("CloseHandle", "Ptr", h)  <em>; 关闭此进程句柄以节约内存.</em>

hModule := DllCall("LoadLibrary", "Str", "Psapi.dll")  <em>; 通过预加载来提升性能.</em>
s := VarSetCapacity(a, s)  <em>; 接收进程列表标识符的数组:</em>
c := 0  <em>; 用于进程标识符的计数器</em>
DllCall("Psapi.dll\EnumProcesses", "Ptr", &amp;a, "UInt", s, "UIntP", r)
Loop, % r // 4  <em>; 把数组解析为 DWORD(32 位) 的标识符:</em>
{
    id := NumGet(a, A_Index * 4, "UInt")
   <em>; 打开进程: PROCESS_VM_READ(0x0010) | PROCESS_QUERY_INFORMATION(0x0400)</em>
    h := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", id, "Ptr")
    if !h
        continue
    VarSetCapacity(n, s, 0)  <em>; 接收模块基础名称的缓存:</em>
    e := DllCall("Psapi.dll\GetModuleBaseName", "Ptr", h, "Ptr", 0, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
    if !e    <em>;  用于 64 位进程在 32 位模式时的回退方法:</em>
        if e := DllCall("Psapi.dll\GetProcessImageFileName", "Ptr", h, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
            SplitPath n, n
    DllCall("CloseHandle", "Ptr", h)  <em>; 关闭进程句柄以节约内存</em>
    if (n &amp;&amp; e)  <em>; 如果映像不是空的, 则添加到列表:</em>
        l .= n . d, c++
}
DllCall("FreeLibrary", "Ptr", hModule)  <em>; 卸载库来释放内存.</em>
<em>;Sort, l, C  ; 取消注释这行来按字母顺序对列表进行排序.</em>
MsgBox, 0, %c% Processes, %l%</pre>
</div>

<div class="ex" id="ListCom">
<p><a class="ex_number" href="#ListCom"></a> 使用 COM 获取正在运行的进程列表.</p>
<pre id="ListCom" class="NoIndent">Gui, Add, ListView, x2 y0 w400 h500, Process Name|Command Line
for proc in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
    LV_Add("", proc.Name, proc.CommandLine)
Gui, Show,, Process List

<em>; Win32_Process: <a href="http://msdn.microsoft.com/en-us/library/aa394372.aspx">http://msdn.microsoft.com/en-us/library/aa394372.aspx</a></em></pre>
</div>

</body>
</html>